﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace Demon
{
    public class NotificationWatcher : IWatcher
    {
        private EventWaitHandle exist_work = 
            new EventWaitHandle(false, EventResetMode.AutoReset);
        private bool work = false;
        private Thread watch_thread = null;
        private List<Notification> notifications = 
                                new List<Notification>();

        public delegate void NotificationDelegate(int id);

        private event NotificationDelegate NotificationEvent;

        private class Notification
        {
            public int EventID { get; private set; }
            public DateTime NotificationTime { get; private set; }

            public Notification(int id, 
                                DateTime time)
            {
                EventID = id;
                NotificationTime = time;
            }
        }

        public NotificationWatcher()
        {
            watch_thread = new Thread(this.QueryCycle)
                {
                    Priority = ThreadPriority.Lowest,
                    ApartmentState = ApartmentState.STA
                };
        }

        bool IWatcher.IsWork
        { get { return work; } }

        void IWatcher.Run()
        {
            if (!work)
            {
                work = true;
                watch_thread.Start();
            }
        }

        void IWatcher.Stop()
        {
            work = false;
            exist_work.Close();
        }

        void IWatcher.AddNotificationHandle(NotificationDelegate handle)
        {
            NotificationEvent += handle;
        }

        public void AddNotification(int id, DateTime time)
        {
            lock (notifications)
                notifications.Add(new Notification(id, time));

            exist_work.Set();
        }

        private void QueryCycle()
        {
            while (work)
            {
                if (notifications.Count == 0)
                    exist_work.WaitOne();
                else
                    for (int i = notifications.Count - 1; i >= 0; --i)
                    {
                        lock (notifications)
                            if (notifications[i].NotificationTime > DateTime.Now)
                            {
                                Notify(notifications[i].EventID);
                                notifications.RemoveAt(i);
                            }
                    }

                Thread.Sleep(TimeSpan.FromSeconds(1f));
            }
        }

        private void Notify(int id)
        {
            if (NotificationEvent != null)
                    NotificationEvent(id);
        }
    }
}
